package cate.game.play.proce.play;

import cate.common.table.d.GDFight;
import cate.common.table.fight.scene.row.FightSceneRow;
import cate.game.fight.FightTaskContext;
import cate.game.play.buff.Buff;
import cate.game.play.config.AllPlayCfg;
import cate.game.play.config.scene.SceneCfg;
import cate.game.play.fighter.Fighter;
import cate.game.play.part.FightSide;
import cate.game.play.part.TeamVS;
import cate.game.play.proce.round.RoundCtx;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteField;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;

@Slf4j
public class PlayCtx {

	@NoteField("剧本模板配置")
	public AllPlayCfg config = new AllPlayCfg();

	@NoteField("剧本")
	public PlayPO po = new PlayPO();

	@NoteField("战斗ctx")
	public FightTaskContext ftc;

	@NoteField("战斗的队伍双方")
	public TeamVS teamVS;

	@NoteField("最大回合数")
	private int roundMax = GDFight.Round.DEFAULT_ROUND_MAX;

	@NoteField("是否是PVP")
	private boolean isPvP;

	public void exe(AllPlayCfg config, FightTaskContext ftc, FightSide a, FightSide b) {
		//战斗前准备
		setUp(config, ftc, a, b);
		//具体战斗的演算
		start();
		//生成剧本后的处理
		end();
	}


	/**
	 * 战前处理
	 */
	private void setUp(AllPlayCfg config, FightTaskContext ftc, FightSide a, FightSide b) {
		this.config = config;
		this.ftc = ftc;
		FightSceneRow sceneRow = getSceneRow();
		if (sceneRow != null) {
			roundMax = sceneRow.roundMax;
			isPvP = sceneRow.isPvP;
			po.expiredDate = LocalDateTime.now().plusDays(sceneRow.replaySaveDay);
			ftc.param.loadSceneCfg(sceneRow);
		} else {
			//没配置默认就存一天
			po.expiredDate = LocalDateTime.now().plusDays(1);
		}
		this.teamVS = new TeamVS(a.ft, b.ft);
		this.po.a = a.ps;
		this.po.b = b.ps;
		this.po.startTime = System.currentTimeMillis();
		this.po.roundMax = roundMax;
		this.po.story = ftc.playStory.copy();
		this.po.story.funcId = ftc.funcId;
		this.ftc.param.beforeFight(this);
		this.teamVS.beforeFight(this);
	}


	/**
	 * 执行演算整个过程，以产出剧本
	 */
	private void start(){
		onFightBegin();
		int roundIndex = GDFight.Round.INDEX_FIRST;
		while (roundIndex <= roundMax) {
			RoundCtx round = new RoundCtx(this, roundIndex);
			round.begin();
			if (this.teamVS.isOver()) {
				return;
			}
			round.ing();
			if (this.teamVS.isOver()) {
				return;
			}
			round.end();
			if (this.teamVS.isOver()) {
				return;
			}
			roundIndex++;
		}
		calWinner();
	}

	private void onFightBegin(){
		this.ftc.param.onFightBegin(this);
		this.teamVS.onFightBegin(this);
		this.po.teamBegin = teamVS.copy();
	}

	private byte calWinner() {
		byte winner = teamVS.getWinnerTeam();
		FightSceneRow row = getSceneRow();
		if (row == null) {
			return winner;
		} else {
			//挑战boss类玩法永远算胜利
			if (row.winnerRule == GDFight.WinnerRule.ALWAYS_A) {
				return GDFight.Team.A;
			}
			//分出胜负后则不需要再额外判断
			if (winner != GDFight.Team.NONE) {
				return winner;
			}
			switch (row.winnerRule) {
				case GDFight.WinnerRule.B_SIDE:
					return GDFight.Team.B;
				case GDFight.WinnerRule.PVP:
					int aliveA = 0;
					long hpA = 0L;
					for (Fighter fighter : teamVS.a.getAllHero()) {
						if (fighter.isAlive()) {
							aliveA++;
							hpA += fighter.attr.hpCur();
						}
					}
					int aliveb = 0;
					long hpB = 0L;
					for (Fighter fighter : teamVS.b.getAllHero()) {
						if (fighter.isAlive()) {
							aliveb++;
							hpB += fighter.attr.hpCur();
						}
					}
					if (aliveA != aliveb) {
						if (aliveA > aliveb) {
							return GDFight.Team.A;
						} else {
							return GDFight.Team.B;
						}
					} else {
						if (hpA > hpB) {
							return GDFight.Team.A;
						} else {
							return GDFight.Team.B;
						}
					}
				case GDFight.WinnerRule.B_LIVE:
					for (Fighter fighter : teamVS.b.getAllHero()) {
						if (fighter.isAlive()) {
							return GDFight.Team.B;
						}
					}
					return GDFight.Team.A;
				default:
					return GDFight.Team.NONE;
			}
		}
	}

	private int idCounter = 0;
	/** 生成战斗对象临时ID */
	private int genId() {
		return ++idCounter;
	}

	/** 注册对象 */
	public void reg(Fighter fighter) {
		fighter.setPid(genId());
	}

	/** 注册buff */
	public void reg(Buff buff) {
		buff.setPid(genId());
	}

	public void addRound(RoundCtx roundCtx) {
		this.po.rounds.add(roundCtx.po);
	}

	private void end() {
		this.po.teamEnd = this.teamVS.copy();
		this.po.winner = calWinner();
		this.po.endTime = this.po.startTime + this.po.playTime();
		this.po.streamline();
	}

	@JsonIgnore
	public AllPlayCfg getCfg(){
		return config;
	}

	//获取战斗场景配置
	private FightSceneRow getSceneRow() {
		SceneCfg cfg = config.scene.get(ftc.funcId);
		if (cfg == null) {
			return null;
		} else {
			return cfg.row;
		}
	}

	public boolean isPvP(){
		return isPvP;
	}
}
